package net.lulihu.common_util.jdbc;

import lombok.extern.slf4j.Slf4j;
import net.lulihu.ObjectKit.*;
import net.lulihu.dateTime.DateTimeKit;
import net.lulihu.common_util.jdbc.annotation.Serializer;
import net.lulihu.exception.ToolBoxException;

import java.lang.reflect.Field;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.util.List;
import java.util.Map;

/**
 * 查询结果集封装
 */
@Slf4j
class QueryResultSetKit {

    /**
     * 查询结果赋值
     *
     * @param resultSet       查询结果集
     * @param result          结果集封装
     * @param resultClass     返回结果的类型
     * @param propertyMapping bean属性与数据表列名称映射 ; key->数据表列名   value->对象属性名称
     * @return 查询结果封装至对应的类中
     */
    static <T> List<T> putResultSet(ResultSet resultSet, List<T> result,
                                    Class<T> resultClass, Map<String, String> propertyMapping)
            throws Exception {
        Long before = null;
        if (log.isDebugEnabled())
            before = DateTimeKit.current(false);

        try {
            int resultType; // 1.基本数据类型 2.封装bean
            if (BeanKit.isPrimitive(resultClass)) resultType = 1;
            else if (BeanKit.isBean(resultClass)) resultType = 2;
            else throw new ToolBoxException("错误的返回值类型【{}】", resultClass);

            return putResultSetToArray(resultType, resultSet, result, resultClass, propertyMapping);
        } finally {
            if (log.isDebugEnabled())
                LogKit.debug(log, "查询封装耗时:{}/ms", DateTimeKit.current(false) - before);
        }
    }

    /**
     * 给返回值为集合的对象赋值
     *
     * @param resultType      返回值类型 1.基本数据类型 2.封装bean
     * @param resultSet       查询结果集
     * @param result          结果集封装
     * @param resultClass     结果集封装
     * @param propertyMapping bean属性与数据表列名称映射 ; key->数据表列名  value->对象属性名称
     * @return 查询结果封装至对应的类中
     */
    @SuppressWarnings("unchecked")
    private static <T> List<T> putResultSetToArray(int resultType, ResultSet resultSet,
                                                   List<T> result, Class<T> resultClass,
                                                   Map<String, String> propertyMapping) throws Exception {
        ResultSetMetaData data = resultSet.getMetaData();

        if (resultType == 1) {
            while (resultSet.next()) {
                result.add((T) resultSet.getObject(1));
            }
        } else {
            while (resultSet.next()) {
                result.add(putResultSet(resultClass, propertyMapping, resultSet, data));
            }
        }
        return result;
    }

    /**
     * 给返回值为 Bean 的赋值
     *
     * @param resultClass     结果封装类型
     * @param propertyMapping bean属性与数据表列名称映射 ; key->数据表列名  value->对象属性名称
     * @param resultSet       查询结果集
     * @param data            查询结果集元数据
     * @return 查询结果封装至对应的类中
     */
    private static <T> T putResultSet(Class<T> resultClass, Map<String, String> propertyMapping,
                                      ResultSet resultSet, ResultSetMetaData data) throws Exception {
        T result = ClassKit.newInstance(resultClass);

        // 列长度
        int count = data.getColumnCount();
        for (int i = 1; i <= count; i++) {
            // 列名称
            String columnName = data.getColumnLabel(i);
            // 通过列名称获取当前行的值
            Object value = resultSet.getObject(columnName);
            // 如果为空值，跳过
            if (value == null) continue;

            // 名称校验
            String fieldName = propertyMapping.get(columnName);
            if (fieldName != null) {
                Field targetField = BeanKit.getPropertyField(resultClass, fieldName);
                // 判断 反序列化
                if (value instanceof byte[]) {
                    Serializer annotation = targetField.getAnnotation(Serializer.class);
                    if (annotation != null) value = KryoKit.readFromByteArray((byte[]) value);
                }
                targetField.set(result, value);
            }
        }
        return result;
    }
}
